#include <iostream>
#include <string>
#include <exception>
#include <stdexcept>

#include "SDL/SDL.h"
#include "SDL/SDL_thread.h"

#include "EventLoop.h"
#include "GameThread.h"
#include "DrawThread.h"


using namespace std;


/*
 * This function is attached to be called on exit of the
 * application with the atexit() function in main() below.
 * Cleans up whatever system resources that have been allocated.
 */
void on_exit()
{
	cout << "Shutting down SDL." << endl;
	SDL_Quit();
}


/*
 * Throw a runtime error exception with a message
 * and the last SDL error description.
 */
void throw_SDL(const string & what)
{
	string s(what);
	s += "\nSDL error: ";
	s += SDL_GetError();
	s += "\n";
	throw runtime_error(s);
}


/*
 * Initializes the video state.
 */
void initVideo()
{
	// Get some info about the current screen resolution etc.
	const SDL_VideoInfo *info = SDL_GetVideoInfo();
	if(!info)
	{
		throw_SDL("Video query failed.");
	}
	// Initialize openGL context.
	// TODO: get screensize from a config file
	int width  = 800;
	int height = 600;
	int bpp    = info->vfmt->BitsPerPixel;
	int flags  = SDL_OPENGL;
	           //| SDL_FULLSCREEN;
	           //| SDL_OPENGLBLIT

	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
	SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
	if( SDL_SetVideoMode(width, height, bpp, flags) == 0 )
	{
		throw_SDL("Video mode set failed.");
	}

	// print some system info
	int tmp;
	cout << "Got screen attributes: " << endl;
	SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE,   &tmp);
	cout << "|   Color bits: " << tmp << endl;
	SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &tmp);
	cout << "|   Double buffer: " << (tmp==1?"On":"Off") << endl;
}


/*
 * Application entry point. Gets SDL and some threads up and running.
 */
int main(int argc, char** argv)
{
	// Initialize various SDL subsystems. Add more flags as needed.
	int sdlflags = SDL_INIT_VIDEO
	             | SDL_INIT_TIMER;
	             //| SDL_INIT_AUDIO
	             //| SDL_INIT_JOYSTICK;
	if(SDL_Init(sdlflags) < 0)
	{
		throw_SDL("Failed to initialize SDL!");
	}
	atexit(on_exit);

	try
	{
		string appName = "GameSkeleton";
		SDL_WM_SetCaption(appName.c_str(), NULL);
		//SDL_SetEventFilter(filterEvents);

		initVideo();

		GameThread gameThread;
		DrawThread drawThread;

		gameThread.start();
		drawThread.start();

		// start event loop here in main thread
		eventLoop();

		cout << "Stopping drawThread" << endl;
		drawThread.stop();
		cout << "Stopping gameThread" << endl;
		gameThread.stop();
		cout << "Stopped all threads." << endl;

		// This is the end of the app if no exceptions have happened.
		exit(0);
	}
	catch(logic_error &e)
	{
		cerr << "Logic error exception was caught in main()!" << endl;
		cerr << e.what() << endl;
	}
	catch(runtime_error &e)
	{
		cerr << "Runtime error exception was caught in main()!" << endl;
		cerr << e.what() << endl;
	}
	catch(exception &e)
	{
		cerr << "General exception was caught in main()!" << endl;
		cerr << e.what() << endl;
	}
	catch(...)
	{
		cerr << "Unknown exception was caught in main()!" << endl;
	}

	// This will only happen after exceptions.
	exit(-1);
}
